#ifndef __EKOS_KERNEL_IPS_H__
#define __EKOS_KERNEL_IPS_H__

struct ips_node_t
{
	 struct
	 {
		  unsigned int status  : 4;
		  unsigned int object  : 20;
		  unsigned int prev    : 20;
		  unsigned int next    : 20;
	 };

	 uint64_t payload;
} __attribute__((packed));

/* FSM for IPS nodes */

#define IPS_FREE          0

#define IPS_SEND_WAIT     1
#define IPS_SEND_BREAKED  2
#define IPS_SEND_FINISHED 3

#define IPS_RECV_WAIT     4
#define IPS_RECV_BREAKED  5
#define IPS_RECV_FINISHED 6

#define IPS_PROC(ips)   ((ips) >> PROCESS_IPS_COUNT_SHIFT)

#define IPS_NULL       0xFFFFFUL
#define IPS_OBJ_NULL   0xFFFFFUL

struct ips_ap_t
{
	 spin_lock_t lock;
	 int free;
	 
	 union
	 {
		  struct
		  {
			   unsigned int wait       : 2;
			   unsigned int queue      : 20;
			   unsigned int send_level : 5;
			   unsigned int recv_level : 5;
		  }; 

		  struct
		  {
			   uint32_t next;
		  };
	 };
} __attribute__((aligned(4)));

#define AP_WAIT_EMPTY   0
#define AP_WAIT_REQUEST 1
#define AP_WAIT_SEND    2
#define AP_WAIT_RECV    3

extern volatile struct ips_node_t *ips_nodes;
extern volatile struct ips_ap_t   *ips_aps;

/* Initialize the ips nodes and ap structure */
int  ips_init(void);
/* Allocate a new ap point with specify recv level and send level */
int  ips_ap_alloc(int send_level, int recv_level);
/* Free a specified ap */
void ips_ap_free(int ap);

/* Recv a send/request to the specified access point */
int ips_recv(int ap, int ips);
/* Try to recv from the ap, do wait if needed */
int ips_recv_try(int ips, uint64_t *payload, int wait);
/* Break the ips blocking */
int ips_recv_break(int ap);

/* Send request to specified access point */
int  ips_request(int ap);

/* Start to send a payload to access point */
int ips_send(int ap, int ips, uint64_t payload);
/* Wait the sending to be finished */
int ips_send_try(int ips, int wait);
/* Break the wait of sending */
int ips_send_break(int ips);

#endif
